import sys
import os
import optparse
import pickle
import img_utils as iu


def usage():
    print """
    ppre game_mode [--draft] [ --stages="dd,dd...." ] [--fatdir=zzzzz]
        game_mode: one in sp, sxs, coop, steal, tp.
                   src dir will be ..\data\levels\<game_mode>
        draft : if true will generate the needed files to runtest the level, ie
                a draft view and collision bitmap
                if false precalculate data for painter, and build collision
        stages: list of numbers stating the stages to rebuild, coma separated,
                quoted (double quoted in windows, single quoted else)
                if not specified, all files ddxxxx in src dir where d digit
        fatdir: dir where auxilary images needed for painter will be cached.
                if not specified, will be <src_dir>\fat
    if stages unspecified, all stages in the dir are candidates
    rebuild is attempted only if output file dont exist or is outdated
    """

def get_valid_params(options, args):

    err = False; basedir=None; game_mode=None; stages=None; draft=None
    known_game_modes = ['sp','coop','sxs', 'steal', 'tp']
    if len(args)<1:
        print 'No game_mode. You must specify one of %s'%known_game_modes
        err = True
    if len(args)>1:
        print 'Extra arguments, check your sintax.'
        err = True

    if not err:
        game_mode = args[0]    
        if game_mode not in known_game_modes:
            print 'Unknown game mode, must be one of %s'%known_game_modes
            err = True

    if not err:
        basedir = os.path.join('..','data','levels')
        if not os.path.exists(basedir):
            print 'Error. Please run from ($gamedir)\src'
            err = True

    if not err:
        src_dir = os.path.join(basedir,game_mode)
        draft = options.draft

        stages = options.stages
        if stages=='':
            tmp = os.listdir(src_dir)
            tmp = [ e[:2] for e in tmp if not os.path.isdir(os.path.join(src_dir,e))]
            tmp = list(set(tmp)) # remove duplicates
            stages = []
            for s in tmp:
                try:
                    int(s)
                    stages.append(s)
                except ValueError:
                    pass
            stages.sort()
        else:
            tmp = stages.split(',')
            stages = []
            for s in tmp:
                s = s.lstrip().rstrip()            
                if len(s)<2:
                    s = '0'+s
                stages.append(s)

        for s in stages:
            try:
                n = int(s)            
            except ValueError:
                print 'Error: bad stage name:%s, must be two digits int'%s
                err = True
        
    return err, basedir, game_mode, stages, draft, options.fat_dir

def must_build(src, dest):
    res = (not os.path.exists(dest) or
           os.path.getmtime(dest)< os.path.getmtime(src))
    return res


def main():
    parser = optparse.OptionParser()
    parser.add_option("--stages", default='',
                      help="stage nums to process (coma separated,quoted)")
    parser.add_option("--nodraft", dest="draft", default=True,
                      help="if ommited builds for quick level test", action="store_false")
    parser.add_option("--fatdir", default='', dest="fat_dir",
                      help="dir to store auxiliary files for painter")
    (options, args) = parser.parse_args()

    err, base_dir, game_mode, stages, draft, fat_dir = get_valid_params(options, args)  
    if err:
        usage()
        sys.exit(0)

    src_dir = os.path.join(base_dir, game_mode)
    for stage in stages:
        print 'stage:', stage
        data = LazyData(src_dir, stage, draft, fat_dir)
        crop_rect = data.get("crop_rect")
        data.get("collision")
        if draft:
            data.get("draft")
        else:
            fim = data.get("fat_image")
            # compose a nice rendered image, crop, save as dd.jpg
            im = fim.paint1((75,42,42), (122,153,39))
            im = iu.crop(im, crop_rect)
            dest = os.path.join(src_dir, "%s.jpg"%stage)
            im.save(dest) #? in small samples too much artifacts, if problems
                          # at real size save as png and convert externally

##def compose1(fim, color_for_white, color_for_black):
##    # black areas in bw will be painted to color_for_black, with intensity
##    # modullated by innerness_8way_black, same for white  
##    # if time allows another pass can add small features (to 'texturize')
##    # with probability correlated to innerness
    
    
class LazyData(object):
    def __init__(self, src_dir, stage, draft, fat_dir):
        self.src_dir = src_dir
        self.stage = stage
        self.draft = draft
        if fat_dir=='':
            self.fat_dir = os.path.join(src_dir,'fat')
        else:
            self.fat_dir = fat_dir
        if not os.path.exists(self.fat_dir):
            os.makedirs(self.fat_dir)
        
        self._cache = {}
        self.white_alias_color = (164, 106, 158, 255)
        self.tmp_dir = os.path.join(src_dir, 'tmp')
        assert os.path.exists(self.tmp_dir)
        
    def get(self, key):
        try:
            return self._cache[key]
        except KeyError:
            self._cache[key] = getattr(self, 'b_'+key)()
            return self._cache[key]
        
    # builders
    def b_msk_raw(self):
        src = os.path.join(self.src_dir, "%s.msk_raw.png"%self.stage)
        return iu.load(src)

    def b_msk_bw(self):
        short = "%s.msk_bw.png"%self.stage
        print 'short:',short
        src = os.path.join(self.src_dir, "%s.msk_raw.png"%self.stage)
        dest = os.path.join(self.tmp_dir, short )
        if must_build(src, dest):
            im = self.get("msk_raw")
            im = iu.conv1_bw(im, self.white_alias_color)
            im.save(dest)
        else:
            im = iu.load(dest)
        return im
        
    def b_crop_rect(self):
        # side efect: collision potentially built
        src = os.path.join(self.src_dir, "%s.crop.png"%self.stage)
        dest = os.path.join(self.tmp_dir, "%s.crop.pkl"%self.stage)
        if must_build(src, dest):
            # invalidate dependecies
            if "collision" in self._cache:
                del self._cache["collision"]
            if "draft" in self._cache:
                del self._cache["draft"]
            if "final" in self._cache:
                del self._cache["final"]
            
            im = iu.load(src)
            rect = iu.get_reference_rect(im, self.white_alias_color)
            f = open(dest, 'wb')
            pickle.dump(rect, f)
            f.close()            
        else:
            f = open(dest, 'rb')
            rect = pickle.load(f)
            f.close()            
        return rect

    def b_collision(self):
        src0 = os.path.join(self.src_dir, "%s.crop.png"%self.stage)
        src1 = os.path.join(self.src_dir, "%s.msk_raw.png"%self.stage)
        dest = os.path.join(self.src_dir, "%s.collision.png"%self.stage)
        _must_build = must_build(src0, dest) or must_build(src1, dest)
        if _must_build:
            im = self.get("msk_bw")
            print "im:",im
            rect = self.get("crop_rect")
            print 'rect:',rect
            im = iu.crop(im, rect)
            print 'croped im:', im
            im.save(dest)
        else:
            im = iu.load(dest)
        return im

    def b_draft(self):
        src0 = os.path.join(self.src_dir, "%s.crop.png"%self.stage)
        src1 = os.path.join(self.src_dir, "%s.msk_raw.png"%self.stage)
        dest = os.path.join(self.src_dir, "%s.jpg"%self.stage)
        _must_build = must_build(src0, dest) or must_build(src1, dest)
        if _must_build:
            im = self.get("msk_raw")
            rect = self.get("crop_rect")
            im = iu.crop(im, rect)
            im.save(dest)
        else:
            im = iu.load(dest)
        return im

    def b_fat_image(self):
        prefix = "%s._"%self.stage
        src = os.path.join(self.tmp_dir, "%s.msk_bw.png"%self.stage)
        src_getmtime = os.path.getmtime(src)
        print 'prefix:', prefix
        im = iu.load(src)
        border_value = 0
        fat_image = iu.FatImg(im, border_value, self.fat_dir)
        fat_image.load_all(prefix=prefix, src_getmtime=src_getmtime)
        return fat_image


if __name__ == '__main__':
    main()
